home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / spar372.zip / DEVICE_F.C < prev    next >
C/C++ Source or Header  |  1993-12-17  |  21KB  |  665 lines

  1. /*
  2. ** $Source: dh1:network/parnet/Sana2/Sources/device_funcs.c,v $
  3. ** $State: Exp $
  4. ** $Revision: 37.2 $
  5. ** $Date: 93/12/17 22:06:23 $
  6. ** $Author: S.A.Pechler $
  7. **
  8. ** Amiga SANA-II Example PARnet device driver.
  9. **
  10. ** General Device functions.
  11. **
  12. ** Based on the Amiga SANA-II Example SLIP device driver code by bj, 
  13. ** which is (C) Copyright 1992 Commodore-Amiga, Inc.
  14. ** the rhslip.device by Olaf Seibert <rhialto@mbfys.kun.nl>, and on
  15. ** the agnet.device code by ppessi <Pekka.Pessi@hut.fi>, which is
  16. ** Copyright (c) 1993 AmiTCP/IP Group,
  17. **                    Helsinki University of Technology, Finland.
  18. **                    All rights reserved.
  19. */
  20.  
  21. #include "device_protos.h"
  22.  
  23. /* Our device name */
  24. const char SPARName[] = SPARDEVNAME;
  25.  
  26. /*
  27. ** Device Open vector
  28. **
  29. ** a1 - SANA2 IO Request
  30. ** a6 - Pointer to our device base
  31. ** d0 - Unit number
  32. ** d1 - Flags
  33. **
  34. */
  35.  
  36. LONG ASM DevOpen(REG(a1) struct IOSana2Req *ios2,
  37.                  REG(a6) struct SPARDevice *SPARDevice,
  38.                  REG(d0) ULONG s2unit,
  39.                  REG(d1) ULONG s2flags)
  40. {
  41.     struct SPARDevUnit *sdu;     /* our unit structure (it could already have been
  42.                                   * initialized on a previous DevOpen() call) */
  43.     struct TagItem *bufftag;     /* Tags for the SANA-II buffer management functions */
  44.     struct Library *UtilityBase; /* utility.library is used for the Tag functions */
  45.     struct BufferManagement *bm; /* Sana-II BufferManagement Buffer Copy functions */
  46.     LONG returncode;
  47.     BOOL status = FALSE;         /* Flag: Initialisation succeeded/failed */
  48.  
  49.     /* Enforce single threading since we may need to Wait() when starting
  50.      * up the Unit process. If somebody decides to DoExpunge() before we
  51.      * get the semaphore, system is probably blowing up anyways.
  52.      */
  53.     ObtainSemaphore(&SPARDevice->sd_Lock); 
  54.  
  55.     SPARDevice->sd_Device.lib_OpenCnt++;   /* So we won't expunge ourselves... */
  56.  
  57.     if(s2unit < SD_MAXUNITS)               /* Legal Unit number? */
  58.     {
  59.       initsyslog();
  60.  
  61.       if(sdu = InitSPARUnit(s2unit))       /* Initialize the Unit */
  62.       {
  63.         if(UtilityBase = OpenLibrary("utility.library",37L)) /* For Tag functions */
  64.         {
  65.         /* Allocate a structure to store the pointers to the callback routines. */
  66.  
  67.         if(bm = AllocMem(sizeof(struct BufferManagement),MEMF_CLEAR|MEMF_PUBLIC))
  68.         {
  69.             /* Note: I don't complain if I can't find pointers to the callback routines.
  70.              * This is because there are some programs that may need to open me, but
  71.              * will never use any device commands that require the callbacks. */
  72.  
  73.             if(bufftag = FindTagItem(S2_CopyToBuff, (struct TagItem *)ios2->ios2_BufferManagement))
  74.                 bm->bm_CopyToBuffer = (SANA2_CTB) bufftag->ti_Data;
  75.  
  76.             if(bufftag = FindTagItem(S2_CopyFromBuff, (struct TagItem *)ios2->ios2_BufferManagement))
  77.                 bm->bm_CopyFromBuffer = (SANA2_CFB) bufftag->ti_Data;
  78.  
  79.             AddTail((struct List *)&sdu->sdu_BuffMgmt,(struct Node *)bm);
  80.  
  81.             /* Everything went okay. */
  82.             status = TRUE;
  83.             returncode = 0;
  84.             SPARDevice->sd_Device.lib_OpenCnt++;
  85.             SPARDevice->sd_Device.lib_Flags &=~LIBF_DELEXP;
  86.             sdu->sdu_Unit.unit_OpenCnt++;
  87.  
  88.             /* Fix up the initial io request */
  89.             ios2->ios2_BufferManagement = (VOID *)bm;
  90.             ios2->ios2_Req.io_Error = 0;
  91.             ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
  92.             ios2->ios2_Req.io_Unit = (struct Unit *)sdu;
  93.             ios2->ios2_Req.io_Device = (struct Device *)SPARDevice;
  94.         }
  95.         CloseLibrary(UtilityBase);
  96.       }
  97.      }
  98.     }
  99.  
  100.     /* See if something went wrong. */
  101.     if(!status)
  102.     {
  103.       ios2->ios2_Req.io_Error = IOERR_OPENFAIL;
  104.       ios2->ios2_Req.io_Unit = (struct Unit *) -1;
  105.       ios2->ios2_Req.io_Device = (struct Device *) -1;
  106.       returncode = IOERR_OPENFAIL;
  107.     }
  108.     SPARDevice->sd_Device.lib_OpenCnt--;
  109.     ReleaseSemaphore(&SPARDevice->sd_Lock);
  110.  
  111.     return(returncode);
  112. }
  113.  
  114. /*
  115. ** Device Close vector.
  116. **
  117. ** a1 - IOReq
  118. ** a6 - Device Pointer
  119. **
  120. ** There are two different things that might be returned from the Close
  121. ** routine.  If the device wishes to be unloaded, the Close should return
  122. ** the segment list (as given to DevInit).  Otherwise close MUST return NULL.
  123. */
  124.  
  125. BPTR ASM DevClose(REG(a1) struct IOSana2Req *ios2,
  126.                   REG(a6) struct SPARDevice *SPARDevice)
  127. {
  128.     struct SPARDevUnit *sdu;
  129.     BPTR seglist = NULL;
  130.  
  131.     ObtainSemaphore(&SPARDevice->sd_Lock);
  132.  
  133.     sdu = (struct SPARDevUnit *)ios2->ios2_Req.io_Unit;
  134.  
  135.     /* I always shut the unit process down if the open count drops to zero.
  136.      * That way, if I need to expunge, I never have to Wait(). */
  137.  
  138.     sdu->sdu_Unit.unit_OpenCnt--;
  139.     if(!sdu->sdu_Unit.unit_OpenCnt)
  140.       ExpungeUnit(sdu);
  141.  
  142.     /* Trash the io_Device and io_Unit fields so that any attempt to use this
  143.      * request will die immediatly. */
  144.  
  145.     ios2->ios2_Req.io_Device = (struct Device *) -1;
  146.     ios2->ios2_Req.io_Unit = (struct Unit *) -1;
  147.  
  148.     SPARDevice->sd_Device.lib_OpenCnt--;
  149.  
  150.     ReleaseSemaphore(&SPARDevice->sd_Lock);
  151.  
  152.     /* Check to see if we've been asked to expunge. */
  153.     if(SPARDevice->sd_Device.lib_Flags & LIBF_DELEXP)
  154.       seglist = DevExpunge(SPARDevice);
  155.  
  156.     return(seglist);
  157. }
  158.  
  159.  
  160. /*
  161. ** Device Expunge vector
  162. **
  163. ** a6 - Device base
  164. **
  165. ** There are two different things that might be returned from the Expunge
  166. ** routine.  If the device is no longer open then Expunge should return the
  167. ** segment list (as given to DevInit). Otherwise Expunge should set the
  168. ** delayed expunge flag (LIBF_DELEXP) and return NULL.
  169. **
  170. ** One other important note: You may NEVER EVER Wait() in expunge. Period.
  171. ** This is because Expunge is called from the memory allocator, A Wait()
  172. ** call would take too long time to complete.
  173. */
  174.  
  175. BPTR ASM DevExpunge(REG(a6) struct SPARDevice *SPARDevice)
  176. {
  177.     BPTR seglist;
  178.     ULONG devbase;
  179.     LONG devbasesize;
  180.  
  181.     if(SPARDevice->sd_Device.lib_OpenCnt)
  182.     {
  183.       /* Sorry, we're busy.  We'll expunge later on if we can. */
  184.       SPARDevice->sd_Device.lib_Flags |= LIBF_DELEXP;
  185.       seglist = (BPTR)NULL;
  186.     }
  187.     else
  188.     {
  189.       /* Free up our library base and function table after
  190.        * removing ourselves from the library list. */
  191.       Remove((struct Node *)SPARDevice);
  192.       seglist = SPARDevice->sd_SegList;
  193.  
  194.       /* Calculate the amount of memory to be FreeMem'ed */
  195.       devbase = (ULONG) SPARDevice;
  196.  
  197.       devbasesize = (ULONG)SPARDevice->sd_Device.lib_NegSize;
  198.       devbase = devbase - devbasesize;
  199.  
  200.       devbasesize += (ULONG)SPARDevice->sd_Device.lib_PosSize;
  201.  
  202.       uninitsyslog();
  203.  
  204.       FreeMem((APTR)devbase,devbasesize);
  205.       ExtDeviceBase = NULL; /* ! */
  206.     }
  207.     return(seglist);
  208. }
  209.  
  210. /*
  211. ** InitSPARUnit
  212. **
  213. ** Initialize (if needed) a new SPAR device Unit and process.
  214. **
  215. */
  216.  
  217. struct SPARDevUnit *InitSPARUnit(ULONG s2unit)
  218. {
  219.     struct SPARDevice *SPARDevice = SPARBase;
  220.     struct SPARDevUnit *sdu;
  221.     struct TagItem NPTags[]={NP_Entry, 0, NP_Name, 0, NP_Priority, SPAR_PRI, TAG_DONE, 0};
  222.     struct MsgPort *replyport;
  223.  
  224.     /* Check to see if the Unit is already up and running.  If
  225.      * it is, just drop through.  If not, try to start it up. */
  226.  
  227.     if(!SPARDevice->sd_Units[s2unit])
  228.     {
  229.       /* Open up dos.library */
  230.  
  231.       if(SPARDevice->sd_DOSBase = OpenLibrary("dos.library",37L))
  232.       {
  233.             /* Allocate a new Unit structure */
  234.             if(sdu = AllocMem(sizeof(struct SPARDevUnit), MEMF_CLEAR|MEMF_PUBLIC))
  235.             {
  236.                 /* Do some initialization on the Unit structure.
  237.                  * We set the Unit's message port to PA_IGNORE until the
  238.                  * new process has a change to set it up.
  239.                  */
  240.                 NewList(&sdu->sdu_Unit.unit_MsgPort.mp_MsgList);
  241.                 sdu->sdu_Unit.unit_MsgPort.mp_Node.ln_Type = NT_MSGPORT;
  242.                 sdu->sdu_Unit.unit_MsgPort.mp_Flags = PA_IGNORE;
  243.                 sdu->sdu_Unit.unit_MsgPort.mp_Node.ln_Name = (char *)SPARName;
  244.  
  245.                 sdu->sdu_UnitNum = s2unit;
  246.                 sdu->sdu_Device = (struct Device *) SPARDevice;
  247.                 sdu->sdu_State = 0;                      /* status: nothing */
  248.  
  249.                 /* Try to read in our configuration file */
  250.                 if(ReadConfig(sdu))
  251.                 {
  252.                     /* Start up the unit process */
  253.                     if(replyport = CreateMsgPort())
  254.                     {
  255.                         SPARDevice->sd_Startup.Msg.mn_ReplyPort = replyport;
  256.                         SPARDevice->sd_Startup.Device = (struct Device *) SPARDevice;
  257.                         SPARDevice->sd_Startup.Unit = (struct Unit *)sdu;
  258.  
  259.                         NPTags[0].ti_Data = (ULONG) &DevProcCEntry; /* Assembly entry point for the unit process. */
  260.                                                                     /* Was DevProcEntry in Spar_device.asm */
  261.                         NPTags[1].ti_Data = (ULONG) SPARName;       /* Process name */
  262.  
  263.                         /* Rhialto: use opener's priority */
  264.                         NPTags[2].ti_Data = (ULONG) FindTask(NULL)->tc_Node.ln_Pri;
  265.  
  266.                         if(sdu->sdu_Proc = CreateNewProc(NPTags))
  267.                         {
  268.                             /* Wait for process setup completion (see DevProcCEntry) */
  269.                             PutMsg(&sdu->sdu_Proc->pr_MsgPort,(struct Message *)&SPARDevice->sd_Startup);
  270.                             WaitPort(replyport);
  271.                             GetMsg(replyport);
  272.                         }
  273.                         DeleteMsgPort(replyport);
  274.                     }
  275.                 }
  276.  
  277.                 if(!sdu->sdu_Proc)
  278.                     /* The Unit process couldn't start for some reason, so free the Unit structure. */
  279.                     FreeMem(sdu,sizeof(struct SPARDevUnit));
  280.                 else
  281.                     /* Set up the Unit structure pointer in the device base */
  282.                     SPARDevice->sd_Units[s2unit] = (struct Unit *)sdu;
  283.             }
  284.  
  285.             debug(("InitSPARUnit: opened unit: %d\n",s2unit))
  286.  
  287.             CloseLibrary(SPARDevice->sd_DOSBase);
  288.         }
  289.  
  290.     }
  291.     debug(("InitSPARUnit: return(%d)\n",SPARDevice->sd_Units[s2unit]))
  292.  
  293.     return((struct SPARDevUnit *)SPARDevice->sd_Units[s2unit]);
  294. }
  295.  
  296. /*
  297. **
  298. ** ExpungeUnit
  299. **
  300. ** Tells a unit process to go away...
  301. **
  302. ** This function is called from the DevClose routine when the open count for a
  303. ** unit reaches zero.  This routine signals the unit process to exit and then
  304. ** waits for the unit process to acknowledge.  The unit structure is then
  305. ** freed.
  306. */
  307.  
  308. VOID ExpungeUnit(struct SPARDevUnit *sdu)
  309. {
  310.     struct SPARDevice *SPARDevice = SPARBase;
  311.     struct Task *unittask;
  312.  
  313.     unittask = (struct Task *)sdu->sdu_Proc;
  314.  
  315.     sdu->sdu_Proc = (struct Process *)FindTask(NULL);
  316.  
  317.     Signal(unittask,SIGBREAKF_CTRL_F);
  318.     Wait(SIGBREAKF_CTRL_F);
  319.  
  320.     SPARDevice->sd_Units[sdu->sdu_UnitNum] = NULL;
  321.  
  322.     FreeMem(sdu, sizeof(struct SPARDevUnit));
  323. }
  324.  
  325. /*
  326. **
  327. ** BeginIO
  328. **
  329. ** This is the dispatch point for the driver's incoming IORequests.
  330. **
  331. ** BeginIO starts all incoming IO.  The IO is either queued up for the
  332. ** unit task or processed immediately.
  333. **
  334. ** IMPORTANT:
  335. ** The exec WaitIO() function uses the IORequest node type (LN_TYPE)
  336. ** as a flag.  If set to NT_MESSAGE, it assumes the request is
  337. ** still pending and will wait.  If set to NT_REPLYMSG, it assumes the
  338. ** request is finished.  It's the responsibility of the device driver
  339. ** to set the node type to NT_MESSAGE before returning to the user.
  340. */
  341.  
  342. /* This define is used to tell which commands should be handled
  343.  * immediately (on the caller's schedule).
  344.  * In this case, no immediate commands are defined.
  345.  */
  346. #define SPAR_IMMEDIATES NULL
  347.  
  348. VOID ASM DevBeginIO(REG(a1) struct IOSana2Req *ios2,
  349.                     REG(a6) struct SPARDevice *SPARDevice)
  350. {
  351.  
  352.     /* set node type: request pending */
  353.     ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  354.  
  355.     /* Check for valid command */
  356.     if(ios2->ios2_Req.io_Command < S2_END)
  357.  
  358.       /* check if this command can be handled immediately */
  359.     if ((ios2->ios2_Req.io_Flags & IOF_QUICK) &&
  360.        ((1L << ios2->ios2_Req.io_Command) & SPAR_IMMEDIATES))
  361.           PerformIO(ios2); /* Process immediately */
  362.       else
  363.       {
  364.           /* Queue up to the unit task */
  365.           ios2->ios2_Req.io_Flags &= ~IOF_QUICK; /* we did NOT complete this quickly */
  366.           PutMsg((struct MsgPort *)ios2->ios2_Req.io_Unit,(struct Message *)ios2);
  367.       }
  368.     else
  369.     {   /* Unknown device command */
  370.         ios2->ios2_Req.io_Error = IOERR_NOCMD;
  371.         TermIO(ios2);
  372.     }
  373. }
  374.  
  375. /*
  376. ** TermIO sends the IO request back to the user.  It knows not to mark
  377. ** the device as inactive if this was an immediate request or if the
  378. ** request was started from the server task.
  379. */
  380. VOID TermIO(struct IOSana2Req *ios2)
  381. {
  382. #ifdef HANDLE_IO_QUICK
  383.    /* check if this was an immediaty request */
  384.    if(!((1L << ios2->ios2_Req.io_Command) & SPAR_IMMEDIATES))
  385.    {
  386.       struct SPARDevUnit *sdu;
  387.       sdu = (struct SPARDevUnit *)ios2->ios2_Req.io_Unit; /* get the Unit pointer */
  388.  
  389.       /* We may need to turn the active bit off, when IO came not from the
  390.        * task */
  391.       if (!(sdu->sdu_Unit.unit_flags & UNITB_INTASK))
  392.       {
  393.         /* The task does not have more work to do */
  394.         sdu->sdu_Unit.unit_flags &= ~UNITB_ACTIVE;
  395.       }
  396.  
  397.       /*
  398.        * Code added from the messydisk.device by Rhialto:
  399.        *
  400.        * The task may have work to do that came in while we were processing
  401.        * in the caller's context.
  402.        */
  403.        if (sdu->sdu_Unit.unit_flags & UNITF_WAKETASK)
  404.        {  sdu->sdu_Unit.unit_flags &= ~UNITF_WAKETASK;
  405.           WakePort(&sdu->sdu_Unit.unit_MsgPort);
  406.        }
  407.  
  408.    }
  409. #endif
  410.  
  411.    /* If the quick bit is still set then we don't need to reply
  412.     * msg, just return to the user. */
  413.  
  414.    if(!(ios2->ios2_Req.io_Flags & IOF_QUICK))
  415.       ReplyMsg((struct Message *)ios2);
  416. }
  417.  
  418. /*
  419. ** The device AbortIO() entry point.
  420. **
  421. ** A1 - The IO request to be aborted.
  422. ** A3 - The unit pointer (NOT!)
  423. ** A6 - The device base.
  424. */
  425. LONG ASM DevAbortIO(REG(a1) struct IOSana2Req *ios2,
  426.                     REG(a6) struct SPARDevice *SPARDevice)
  427. {
  428.     struct SPARDevUnit *sdu = (struct SPARDevUnit *)ios2->ios2_Req.io_Unit;
  429.     LONG result = NULL;
  430.  
  431.     ObtainSemaphore(&sdu->sdu_ListLock);
  432.     if(ios2->ios2_Req.io_Message.mn_Node.ln_Type != NT_REPLYMSG)
  433.       switch(ios2->ios2_Req.io_Command)
  434.       {
  435.         case CMD_READ:      result=AbortReq(&sdu->sdu_Rx,ios2);
  436.                             break;
  437.  
  438.         case CMD_WRITE:     result=AbortReq(&sdu->sdu_Tx,ios2);
  439.                             break;
  440.  
  441.         case S2_READORPHAN: result=AbortReq(&sdu->sdu_RxOrph,ios2);
  442.                             break;
  443.  
  444.         case S2_ONEVENT:    result=AbortReq(&sdu->sdu_Events,ios2);
  445.                             break;
  446.  
  447.         default:            result=IOERR_NOCMD;
  448.                             break;
  449.       }
  450.     ReleaseSemaphore(&sdu->sdu_ListLock);
  451.     return(result);
  452. }
  453.  
  454.  
  455. /*
  456. ** This routine is called whenever a CMD_WRITE request
  457. ** has returned from the PARnet driver.
  458. */
  459. VOID ServiceTxPort(struct SPARDevUnit *sdu, struct IOParReq *IOPar)
  460. {
  461.     struct IOSana2Req *ios2;
  462.  
  463.     if(IOPar->io_Error) /* a write timeout occured */
  464.         PacketDropped(sdu);
  465.  
  466.     if(sdu->sdu_State & SPARUF_ONLINE)
  467.     {
  468.       /* Get next CMD_WRITE request (if present) */
  469.       ObtainSemaphore(&sdu->sdu_ListLock);
  470.       ios2 = (struct IOSana2Req *)RemHead((struct List *)&sdu->sdu_Tx);
  471.       ReleaseSemaphore(&sdu->sdu_ListLock);
  472.  
  473.       if(ios2)       /* Is a CMD_WRITE request pending? */
  474.       {
  475.           SendPacket(sdu, ios2);
  476.           sdu->sdu_NoMore = TRUE;  /* There might be more */
  477.       }
  478.     }
  479.     else
  480.       sdu->sdu_NoMore = TRUE;
  481. }
  482.  
  483. /*
  484. ** This routine is called whenever a CMD_READ request
  485. ** returns from the PARnet driver.
  486. */
  487. VOID DoPARnet(struct SPARDevUnit *sdu, struct IOParReq *IOPar)
  488. {
  489.     /* Check if received data is valid in size */
  490.  
  491.     /* Not to small? */
  492.     if (IOPar->io_Actual < SHDR_LEN) ReceivedGarbage(sdu);
  493.     else
  494.     {
  495.        IOPar->io_Length=IOPar->io_Actual;
  496.  
  497.        /* Not too large? */
  498.        if(IOPar->io_Length > SPAR_MTU) PacketOverrun(sdu);
  499.        else GotPacket(sdu,IOPar->io_Length);
  500.     }
  501.     /* Queue up another CMD_READ request...*/
  502.     QueueParRequest(sdu);
  503. }
  504.  
  505. /*
  506. ** This is the C entry point for the Unit process.
  507. ** A6 has been set up by the assembly stub in spar_device.asm.
  508. */
  509.  
  510. VOID ASM DevProcCEntry(VOID)
  511. {
  512.     struct Process *proc;
  513.     struct SPARDevUnit *sdu;
  514.     struct IOParReq *iopar;
  515.     struct StartupMessage *sm;
  516.     struct BufferManagement *bm;
  517.     struct IOSana2Req *ios2;
  518.     ULONG waitmask,signals;
  519.     UBYTE signalbit;
  520.  
  521.     /* Find our Process pointer and wait for our startup
  522.        message to arrive. */
  523.  
  524.     proc = (struct Process *)FindTask(NULL);
  525.  
  526.     WaitPort(&proc->pr_MsgPort);
  527.  
  528.     /* Pull the startup message off of our process messageport. */
  529.     sm = (struct StartupMessage *)GetMsg(&proc->pr_MsgPort);
  530.  
  531.     /* Grab our Unit pointer. */
  532.     sdu = (struct SPARDevUnit *)sm->Unit;
  533.  
  534.     /* Attempt to allocate a signal bit for our Unit MsgPort. */
  535.     signalbit = AllocSignal(-1L);
  536.     if(signalbit != -1)
  537.     {
  538.       /* Set up our Unit's MsgPort. */
  539.       sdu->sdu_Unit.unit_MsgPort.mp_SigBit = signalbit;
  540.       sdu->sdu_Unit.unit_MsgPort.mp_SigTask = (struct Task *)proc;
  541.       sdu->sdu_Unit.unit_MsgPort.mp_Flags = PA_SIGNAL;  /* make it "live" */
  542.  
  543.       /* Initialize our list semaphore */
  544.       InitSemaphore(&sdu->sdu_ListLock);
  545.  
  546.       /* Initialize our linked lists. */
  547.       NewList((struct List *)&sdu->sdu_Rx);
  548.       NewList((struct List *)&sdu->sdu_RxOrph);
  549.       NewList((struct List *)&sdu->sdu_Tx);
  550.       NewList((struct List *)&sdu->sdu_Events);
  551.       NewList((struct List *)&sdu->sdu_BuffMgmt);
  552.       NewList((struct List *)&sdu->sdu_Track);
  553.  
  554.       /* Initialize the PARnet stuff.  If all goes okay,
  555.        * set sdu->sdu_Proc to pointer to our unit process.
  556.        * This will let the Unit init code know that were
  557.        * are okay. */
  558.  
  559.       if(InitPARnet(sdu))
  560.             sdu->sdu_Proc = proc;
  561.     }
  562.     /* Initialization done. Reply to our startup message (see InitSparUnit),
  563.      * so they can continue */
  564.  
  565.     ReplyMsg((struct Message *)sm);
  566.  
  567.     /* Check sdu->sdu_Proc to see if everything went okay up above. */
  568.     if(sdu->sdu_Proc)
  569.     {
  570.       waitmask = (1L<<signalbit) | (1L<<sdu->sdu_RxPort->mp_SigBit) |
  571.            (1L<<sdu->sdu_TxPort->mp_SigBit) | SIGBREAKF_CTRL_F;
  572.  
  573.       /* Loop...*/
  574.  
  575.       while(TRUE)
  576.       {
  577.          signals = Wait(waitmask);
  578.  
  579.          /* Have we been signaled to shut down? */
  580.          if(signals & SIGBREAKF_CTRL_F)
  581.          break;
  582.  
  583. #ifdef HANDLE_IO_QUICK
  584.     /*
  585.      * Lock the device. If it fails, we have set a flag such that the
  586.      * TermIO wakes us again.
  587.      */
  588.     sdu->sdu_Unit.unit_flags |= UNITF_WAKETASK;
  589.     if (BSET_ACTIVE(&sdu->sdu_Unit.unit_flags))
  590.         continue;
  591.  
  592.     sdu->sdu_Unit.unit_flags |= UNITF_INTASK;
  593. #endif
  594.  
  595.          /* I use this flag to make sure I don't sit idle
  596.           * with a message sitting on one of my message ports. */
  597.  
  598.             sdu->sdu_NoMore = TRUE;  /* Make sure we run at least once. */
  599.  
  600.             while(sdu->sdu_NoMore)
  601.             {
  602.                 sdu->sdu_NoMore = FALSE;
  603.  
  604.                 /* Handle messages from the user (were queued in DevBeginIO) */
  605.                 if(ios2 = (struct IOSana2Req *)GetMsg((struct MsgPort *)sdu))
  606.                 {
  607.                     sdu->sdu_NoMore = TRUE; /* there might be more */
  608.                     PerformIO(ios2);        /* process an io request */
  609.                 }
  610.  
  611.                 /* Handle message from the receiver */
  612.                 if(iopar = (struct IOParReq *)GetMsg(sdu->sdu_RxPort))
  613.                     if(sdu->sdu_State & SPARUF_ONLINE)
  614.                     {
  615.                       sdu->sdu_NoMore = TRUE; /* there might be more? */
  616.                       DoPARnet(sdu, iopar);
  617.                     }
  618.  
  619.                 /* Handle message from the transmitter */
  620.                 if(iopar = (struct IOParReq *)GetMsg(sdu->sdu_TxPort))
  621.                 {
  622.                   sdu->sdu_NoMore = TRUE;    /* there might be more? */
  623.                   ServiceTxPort(sdu, iopar);
  624.                 }
  625.             }
  626.         }
  627.  
  628. #ifdef HANDLE_IO_QUICK
  629.         sdu->sdu_Unit.unit_flags &= ~(UNITF_ACTIVE | UNITF_INTASK | UNITF_WAKETASK);
  630. #endif
  631.         /* No more messages on my port */
  632.         /* If we're online, we need to shut everything down. */
  633.         if(sdu->sdu_State & SPARUF_ONLINE)
  634.         {
  635.             ClosePARnet(sdu);
  636.             FreeSignal((long)signalbit);
  637.             while(bm = (struct BufferManagement *)RemHead((struct List *)&sdu->sdu_BuffMgmt))
  638.             FreeMem(bm,sizeof(struct BufferManagement));
  639.         }
  640.         DeinitPARnet(sdu);
  641.  
  642.         /* Signal the other side we're exiting.  Make sure that
  643.            we exit before they wake up by using the same trick
  644.            when replying to Workbench startup messages. */
  645.  
  646.         Forbid();
  647.         Signal((struct Task *)sdu->sdu_Proc,SIGBREAKF_CTRL_F);
  648.     }
  649.     /* Something went wrong in the init code.  Drop out. */
  650.     else
  651.     {
  652.       if(signalbit)
  653.           FreeSignal((long)signalbit);
  654.     }
  655. }
  656.  
  657. /* List init routine. */
  658. VOID NewList(struct List *list)
  659. {
  660.     list->lh_Head = (struct Node *)&list->lh_Tail;
  661.     list->lh_Tail = NULL;
  662.     list->lh_TailPred = (struct Node *)list;
  663. }
  664.  
  665.